﻿using SharpDepend.Datatypes;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace SharpDepend
{
    public sealed class GraphicDevice
    {
        public System.Type GraphicsDeviceType { get; private set; }

        public string DeviceName { get; private set; }

        public GraphicDevice(System.Type graphicsDeviceType, string deviceName)
        {
            GraphicsDeviceType = graphicsDeviceType;
            DeviceName = deviceName;
        }

        public override string ToString()
        {
            return DeviceName;
        }
    }

    public interface IGraphicsDevice
    {
        bool ManualRendering { get; }

        event Action OnManualRender;

        IGraphicsDisplay GraphicsDisplay { get; }

        event Action ResolutionChanged;

        /// <summary>
        /// Calls wqhen this instance has been created.
        /// </summary>
        /// <param name="graphicsDisplay"></param>
        void Initialize(IGraphicsDisplay graphicsDisplay);

        /// <summary>
        /// Set the view port size.
        /// </summary>
        /// <param name="width">Width in pixels.</param>
        /// <param name="height">Height in pixels.</param>
        void SetViewportSize(double width, double height);

        /// <summary>
        /// Get collection of loaded textures.
        /// </summary>
        ReadOnlyCollection<Texture> Textures { get; }

        bool Ready { get; }

        /// <summary>
        /// Get or set the enabled of rendering.
        /// </summary>
        bool Enable { get; set; }

        bool RenderTextures { get; set; }

        int RenderWidth { get; }

        int RenderHeight { get; }

        void RegisterTexture(Texture texture);

        void UnregisterTexture(Texture texture);

        void UpdateTexture(Texture texture);

        void BeginRender();

        void SetClip(Vector4 plane);

        void ResetClip();

        void Draw(ref Vector4 rectangle, Color color);

        void Draw(ref Vector4 rectangle, Color color, Texture texture, ref Vector4 destinationTextureUV);

        void DrawLine(Vector2 start, Vector2 end, Color color);

        void DrawCircle(Vector2 position, double radius, Color color);

        void DrawTriangles(FastStructList<Vector2> vertices, FastStructList<ushort> indices, FastStructList<Color> colors);

        void EndRender();

        void DisposeDevice();
    }

    public static class GraphicsDeviceHelper
    {
        public static void Draw(this IGraphicsDevice gd, Vector4 rectangle, Color color)
        {
            gd.Draw(ref rectangle, color);
        }

        public static void Draw(this IGraphicsDevice gd, Vector4 rectangle, Color color, Texture texture)
        {
            Vector4 textureDestination = texture.Dimension;
            gd.Draw(ref rectangle, color, texture, ref textureDestination);
        }
    }

    public interface IGraphicsDisplay : Classes.ITouchListener
    {
        event Action DeviceLoaded;

        event Action DeviceUnloaded;

        object Locker { get; }

        bool Ready { get; }

        /// <summary>
        /// Get or set the manual graphics device. If null tha graphics will be automatic changable.
        /// </summary>
        IGraphicsDevice ManualGraphicsDevice { get; set; }

        void GraphicsDeviceChanged(IGraphicsDevice device);

        IGraphicsDevice GraphicsDevice { get; }

        bool Enable { get; set; }

        bool RenderTextures { get; set; }

        void RegisterTexture(Texture texture);

        void UnregisterTexture(Texture texture);

        bool ContainsTexture(Texture texture);
    }

    public interface IGraphicsDisplayManager
    {
        GraphicDevice CurrentUsingDevice { get; }

        IGraphicsDisplay CreateGraphicsDisplay();

        IGraphicsDevice CreateDevice(GraphicDevice device);

        void SetGraphicsDevice(GraphicDevice device);

        void AddDevice(GraphicDevice device);

        void SetupDisplay(IGraphicsDisplay display);

        void AddMultitouch(IGraphicsDisplay display);

        IEnumerable<GraphicDevice> AvailableDevices { get; }

        IEnumerable<IGraphicsDisplay> GraphicsDisplaysInUse { get; }
    }

    public static class IGraphicsDisplayManagerHelper
    {
        public static GraphicDevice Find(this IGraphicsDisplayManager gdm, string byName)
        {
            foreach (var device in gdm.AvailableDevices)
            {
                if (device.DeviceName.Equals(byName))
                {
                    return device;
                }
            }

            return null;
        }
    }
}
